package com.wyh.service.serviceImpl.g3serviceimpl;

import com.wyh.domain.dto.g3dto.BuildingEstateArrearsDto;
import com.wyh.domain.dto.g3dto.CustomerPayDetailDto;
import com.wyh.domain.dto.g3dto.G3OrganizationDto;
import com.wyh.domain.po.g3po.AllChargeRate;
import com.wyh.domain.po.g3po.BuildEstateArrears;
import com.wyh.domain.po.g3po.ChargeProjectRate;
import com.wyh.domain.po.g3po.CustomerPayDetail;
import com.wyh.domain.vo.g3vo.ChargeTypeVo;
import com.wyh.domain.vo.g3vo.PropertyManagementVO;
import com.wyh.mapper.g3mapper.BuildEstateArrearsMapper;
import com.wyh.mapper.g3mapper.CustomerBuildingMapper;
import com.wyh.mapper.g3mapper.G3ProjectMapper;
import com.wyh.service.g3service.AsyncService;
import com.wyh.utils.g3utils.ProjectUtils;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AsyncServiceImpl implements AsyncService {
    @Autowired
    private G3ProjectMapper g3ProjectMapper;
    @Autowired
    private BuildEstateArrearsMapper buildEstateArrearsMapper;
    @Autowired
    private CustomerBuildingMapper customerBuildingMapper;
    private PropertyManagementVO propertyManagementVO = new PropertyManagementVO();
    private ChargeTypeVo chargeTypeVo = new ChargeTypeVo();

    @Async("asyncServiceExecutor")
    @Override
    public Future<PropertyManagementVO> selectFirst(G3OrganizationDto g3OrganizationDto) {
        List<Integer> id = new ArrayList<>();
        id.add(g3OrganizationDto.getId());
         List<Integer> result = new ArrayList<>();
        findAllOrganizationId(id,result );
        g3OrganizationDto.setIdList(result);
        // 1.异步任务
        //查询管理的楼盘
        Integer integer = g3ProjectMapper.selectmanagedEstate(g3OrganizationDto);
        if (integer == null) {
            integer = 0;
        }
        //查询在管面积
        Integer managedArea = g3ProjectMapper.selectmanagedArea(g3OrganizationDto);
        if (managedArea == null) {
            managedArea = 0;
        }
        //查询客户数量
        Integer customerCount = g3ProjectMapper.selectCustomerCount(g3OrganizationDto);
        if (customerCount == null) {
            customerCount = 0;
        }
        //查询房屋套数量
        Integer houseCount = g3ProjectMapper.selectHouseCount(g3OrganizationDto);
        if (houseCount == null) {
            houseCount = 0;
        }
        //进行非空判断,避免空指针异常

        propertyManagementVO.setManagedEstate(integer);
        propertyManagementVO.setManagedArea(managedArea);
        propertyManagementVO.setCustomerCount(customerCount);
        propertyManagementVO.setHouseCount(houseCount);


        //3.将结果返回
        return new AsyncResult<>(propertyManagementVO);
    }

    @Async("asyncServiceExecutor")
    @Override
    public Future<PropertyManagementVO> selectSecond(G3OrganizationDto g3OrganizationDto) {
        List<Integer> id = new ArrayList<>();
        id.add(g3OrganizationDto.getId());
        List<Integer> result = new ArrayList<>();
        findAllOrganizationId(id,result );
        g3OrganizationDto.setIdList(result);
        //查询停车场数量

        Integer parkingSpaceCount = g3ProjectMapper.selectParkingSpaceCount(g3OrganizationDto);
        //将查询的结果添加到集合
        if (parkingSpaceCount == null) {
            parkingSpaceCount = 0;
        }
        //查询本月收款金额
        Double currentMonthCollectionAmount = g3ProjectMapper.selectCurrentMonthCollectionAmount(g3OrganizationDto);
        if (currentMonthCollectionAmount == null) {
            currentMonthCollectionAmount = 0.0;
        }
        //查询上月收款金额
        Double lastMonthCollectionAmount = g3ProjectMapper.selectLastMonthCollectionAmount(g3OrganizationDto);
        if (lastMonthCollectionAmount == null) {
            lastMonthCollectionAmount = 0.0;
        }
        //计算本月月环比
        Double currentMonthRatio = ProjectUtils.calculateMonthRatio(currentMonthCollectionAmount, lastMonthCollectionAmount);

        //查询本月欠费金额
        Double currentMonthArrearsAmount = g3ProjectMapper.selectCurrentMonthArrearsAmount(g3OrganizationDto);
        if (currentMonthArrearsAmount == null) {
            currentMonthArrearsAmount = 0.0;
        }
        //查询上个月欠费金额
        Double lastMonthArrearsAmount = g3ProjectMapper.selectLastMonthArrearsAmount(g3OrganizationDto);
        if (lastMonthArrearsAmount == null) {
            lastMonthArrearsAmount = 0.0;
        }
        //计算本月欠费月环比
        Double arrearsRatio = ProjectUtils.calculateMonthRatio(currentMonthArrearsAmount, lastMonthArrearsAmount);

        //查询本月欠费户数
        Integer currentMonthArrearsHouseholds = g3ProjectMapper.selectCurrentMonthArrearsHouseholds(g3OrganizationDto);
        if (currentMonthArrearsHouseholds == null) {
            currentMonthArrearsHouseholds = 0;
        }
        //查询上月欠费户数
        Integer lastMonthArrearsHouseholds = g3ProjectMapper.selectLastMonthArrearsHouseholds(g3OrganizationDto);
        if (lastMonthArrearsHouseholds == null) {
            lastMonthArrearsHouseholds = 0;
        }
        //计算本月欠费户数同期比
        Double arrearsHouseholdYoy = ProjectUtils.calculateMonthRatio(currentMonthArrearsHouseholds.doubleValue(), lastMonthArrearsHouseholds.doubleValue());
        //查询本月开票金额
        Double currentMonthInvoiceAmount = g3ProjectMapper.selectCurrentMonthInvoiceAmount(g3OrganizationDto);
        if (currentMonthInvoiceAmount == null) {
            currentMonthInvoiceAmount = 0.0;
        }
        //查询同期开票金额
        Double lastMonthInvoiceAmount = g3ProjectMapper.selectLastMonthInvoiceAmount(g3OrganizationDto);
        if (lastMonthInvoiceAmount == null) {
            lastMonthInvoiceAmount = 0.0;
        }
        //查询开票金额同期比
        Double invoiceRatio = ProjectUtils.calculateMonthRatio(currentMonthInvoiceAmount, lastMonthInvoiceAmount);


        propertyManagementVO.setParkingSpaceCount(parkingSpaceCount);
        propertyManagementVO.setCurrentMonthCollectionAmount(currentMonthCollectionAmount);
        propertyManagementVO.setLastMonthCollectionAmount(lastMonthCollectionAmount);
        propertyManagementVO.setCurrentMonthCollectionAmountMoM(currentMonthRatio);
        propertyManagementVO.setCurrentMonthArrearsAmount(currentMonthArrearsAmount);
        propertyManagementVO.setLastMonthArrearsAmount(lastMonthArrearsAmount);
        propertyManagementVO.setCurrentMonthArrearsAmountMoM(arrearsRatio);
        propertyManagementVO.setCurrentMonthArrearsHouseholds(currentMonthArrearsHouseholds);
        propertyManagementVO.setLastMonthArrearsHouseholds(lastMonthArrearsHouseholds);
        propertyManagementVO.setCurrentMonthArrearsHouseholdsYoY(arrearsHouseholdYoy);
        propertyManagementVO.setCurrentMonthInvoiceAmount(currentMonthInvoiceAmount);
        propertyManagementVO.setLastMonthInvoiceAmount(lastMonthInvoiceAmount);
        propertyManagementVO.setCurrentMonthInvoiceAmountYoY(invoiceRatio);
        return new AsyncResult<>(propertyManagementVO);
    }

    @Async("asyncServiceExecutor")
    @Override
    public Future<ChargeTypeVo> selectChargeType(G3OrganizationDto g3OrganizationDto) {
        List<Integer> id = new ArrayList<>();
        id.add(g3OrganizationDto.getId());
        List<Integer> result = new ArrayList<>();
        findAllOrganizationId(id,result );
        g3OrganizationDto.setIdList(result);
        //时间校验并调整
        ProjectUtils.checkTime(g3OrganizationDto, g3OrganizationDto.getBeginTime(), g3OrganizationDto.getEndTime());
        g3OrganizationDto.setIdList(result);
        Double calculateOtherFee = 0.0;
        if (g3OrganizationDto.getBeginTime() == null || g3OrganizationDto.getEndTime() == null) {
            g3OrganizationDto.setBeginTime(LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).toString());
            g3OrganizationDto.setEndTime(LocalDateTime.now().toString());

        }
        //查询物业费
        Double propertyFee = g3ProjectMapper.selectPropertyFee(g3OrganizationDto);
        if (propertyFee == null) {
            propertyFee = 0.0;
        }
        calculateOtherFee += propertyFee;
        chargeTypeVo.setPropertyFee(propertyFee);

        //计算物业费占比
        //水电费
        Double waterAndElectricityFee = g3ProjectMapper.selectWaterAndElectricityFee(g3OrganizationDto);
        if (waterAndElectricityFee == null) {
            waterAndElectricityFee = 0.0;
        }
        calculateOtherFee += waterAndElectricityFee;
        chargeTypeVo.setWaterAndElectricityFee(waterAndElectricityFee);
        //查询服务费
        Double serviceFee = g3ProjectMapper.selectServiceFee(g3OrganizationDto);
        if (serviceFee == null) {
            serviceFee = 0.0;
        }
        calculateOtherFee += serviceFee;
        chargeTypeVo.setServiceFee(serviceFee);
        //查询停车费
        Double parkingFee = g3ProjectMapper.selectParkingFee(g3OrganizationDto);
        if (parkingFee == null) {
            parkingFee = 0.0;
        }
        calculateOtherFee += parkingFee;
        chargeTypeVo.setParkingFee(parkingFee);
        //查询广告费
        Double advertisingFee = g3ProjectMapper.selectAdvertisingFee(g3OrganizationDto);
        if (advertisingFee == null) {
            advertisingFee = 0.0;
        }
        calculateOtherFee += advertisingFee;
        chargeTypeVo.setAdvertisingFee(advertisingFee);
        //查询全部费用
        Double incomeStatistics = g3ProjectMapper.selectIncomeStatistics(g3OrganizationDto);
        if (incomeStatistics == null) {
            incomeStatistics = 0.0;
        }
        chargeTypeVo.setIncomeStatistics(incomeStatistics);
        //计算其他费用
        double otherFee = incomeStatistics - calculateOtherFee;
        chargeTypeVo.setOtherFee(otherFee);

        //2.1计算费用占比
        Double properFeePercentage = ProjectUtils.calculateFeePercentage(propertyFee, incomeStatistics);
        Double waterAndElectricityFeePercentage = ProjectUtils.calculateFeePercentage(waterAndElectricityFee, incomeStatistics);
        Double serviceFeePercentage = ProjectUtils.calculateFeePercentage(serviceFee, incomeStatistics);
        Double parkingFeePercentage = ProjectUtils.calculateFeePercentage(parkingFee, incomeStatistics);
        Double advertisingFeePercentage = ProjectUtils.calculateFeePercentage(advertisingFee, incomeStatistics);
        Double otherFeePercentage = ProjectUtils.calculateFeePercentage(otherFee, incomeStatistics);
        //2.2将计算结果封装到chargeTypeVo中
        chargeTypeVo.setPropertyFeePercentage(properFeePercentage);
        chargeTypeVo.setWaterAndElectricityFeePercentage(waterAndElectricityFeePercentage);
        chargeTypeVo.setServiceFeePercentage(serviceFeePercentage);
        chargeTypeVo.setParkingFeePercentage(parkingFeePercentage);
        chargeTypeVo.setAdvertisingFeePercentage(advertisingFeePercentage);
        chargeTypeVo.setOtherFeePercentage(otherFeePercentage);
        return new AsyncResult<>(chargeTypeVo);
    }

    @Async("asyncServiceExecutor")
    @Override
    public Future<List<ChargeProjectRate>> selectChargeRate(G3OrganizationDto g3OrganizationDto) {
        List<ChargeProjectRate> chargeProjectRates = new ArrayList<>();
        if (g3OrganizationDto.getIsCurrentMonth() == 1) {
            chargeProjectRates = g3ProjectMapper.selectChargeRate(g3OrganizationDto);
        } else if (g3OrganizationDto.getIsCurrentMonth() == 0) {
            chargeProjectRates = g3ProjectMapper.selectLastChargeRate(g3OrganizationDto);
        }
        return new AsyncResult<>(chargeProjectRates);
    }

    @Async("asyncServiceExecutor")
    @Override
    public Future<List<AllChargeRate>> selectAllChargeRate(G3OrganizationDto g3OrganizationDto) {
        List<AllChargeRate> allChargeRates = g3ProjectMapper.selectAllChargeRate(g3OrganizationDto);
        return new AsyncResult<>(allChargeRates);
    }


    @Async("asyncServiceExecutor")
    @Override
    public Future<List<BuildEstateArrears>> selectProjectArrears(BuildingEstateArrearsDto buildingEstateArrearsDto) {
        //构造Page参数,调用mapper获取查询信息
        List<BuildEstateArrears> buildEstateArrears = buildEstateArrearsMapper.selectArrearsPage(buildingEstateArrearsDto);
        return new AsyncResult<>(buildEstateArrears);
    }
    @Async("asyncServiceExecutor")
    @Override
    public Future<Long> selectAllTotal(BuildingEstateArrearsDto buildingEstateArrearsDto) {
        Long totalFeesCount = buildEstateArrearsMapper.getTotalFeesCount(buildingEstateArrearsDto);

        return new AsyncResult<>(totalFeesCount);
         }

    @Async("asyncServiceExecutor")
    @Override
    public Future<List<CustomerPayDetail>> selectCustomerArrears(CustomerPayDetailDto customerPayDetailDto) {
        //设置Dto里的时间
        setCustomerPayTime(customerPayDetailDto);

        //欠费一到三个月的详细情况
        List<CustomerPayDetail> oneAndThreePayDetails = customerBuildingMapper.selectCustomerOnePayDetail(customerPayDetailDto);
        //欠费四到六个月的详细情况
        List<CustomerPayDetail> fourAndSixPayDetails = customerBuildingMapper.selectCustomerFourPayDetail(customerPayDetailDto);
        //欠费六个月以上的详细情况
        List<CustomerPayDetail> sixPayDetails = customerBuildingMapper.selectCustomerSixPayDetail(customerPayDetailDto);
        //将三个流进行合
        if (oneAndThreePayDetails == null && fourAndSixPayDetails != null) {
            oneAndThreePayDetails = fourAndSixPayDetails;
        } else if (oneAndThreePayDetails == null && fourAndSixPayDetails == null && sixPayDetails != null) {
            oneAndThreePayDetails = sixPayDetails;
        } else if (oneAndThreePayDetails == null && fourAndSixPayDetails == null && sixPayDetails == null) {
            return new AsyncResult<>(null);
        }
        List<CustomerPayDetail> collect; //最终集合
        //用来存储直接加入的集合
        List<CustomerPayDetail> finalCollect = new ArrayList<>();
        //合并一和二
        collect = getOneAndTwoCollect(oneAndThreePayDetails, fourAndSixPayDetails, finalCollect);
        merge(collect, finalCollect);
        //合并一和三
        collect = getOneAndThreeCollect(collect, sixPayDetails, finalCollect);
        merge(collect, finalCollect);
        return new AsyncResult<>(collect);
    }

    private void setCustomerPayTime(CustomerPayDetailDto customerPayDetailDto) {
        //获取当前时间的
        LocalDate now = LocalDate.now();
        //设置1-3个月的结束时间开始时间
        customerPayDetailDto.setOneToThreeEndMonth(now.toString());
        //设置1-3个月的开始时间
        LocalDate OneToThreeMonth = now.minusMonths(3).withDayOfMonth(1);
        customerPayDetailDto.setOneToThreeBeginMonth(OneToThreeMonth.toString());

        //设置4-6个月的结束时间
        LocalDate FourToSixMonth = now.minusMonths(4).with(TemporalAdjusters.lastDayOfMonth());
        customerPayDetailDto.setFourToSixMonthEndMonth(FourToSixMonth.toString());
        //设置4-6个月的开始时间
        LocalDate FourToSixEndMonth = now.minusMonths(6).withDayOfMonth(1);
        customerPayDetailDto.setFourToSixBeginMonth(FourToSixEndMonth.toString());
        //设置6个月以上的开始时间
        LocalDate SixAboveMonth = now.minusMonths(6).withDayOfMonth(1);
        customerPayDetailDto.setSixMonthFeesBeginAbove(SixAboveMonth.toString());
    }

    //将临时集合的值放入到最终集合中
    private void merge(List<CustomerPayDetail> collect, List<CustomerPayDetail> finalCollect) {
        //将临时结果添加到最终集合里
        if (finalCollect != null){
            //将findCollect里的值去重在加入到最终集合里
        collect.addAll(finalCollect.stream().distinct().collect(Collectors.toList()));
        //清空临时集合
            finalCollect.clear();
        }
    }

    //用于将两个集合合并,并且将相同的资源和项目合并到一起,不同的就添加到临时集合里
    private List<CustomerPayDetail> getOneAndTwoCollect(List<CustomerPayDetail> oneAndThreePayDetails, List<CustomerPayDetail> fourAndSixPayDetails, List<CustomerPayDetail> finalCollect) {
        Map<Boolean, List<CustomerPayDetail>> partitionedDetails = fourAndSixPayDetails.stream()
                .collect(Collectors.partitioningBy(four -> oneAndThreePayDetails.stream()
                        .anyMatch(one -> Objects.equals(one.getType(), four.getType()) && Objects.equals(one.getResource(), four.getResource()))));

        List<CustomerPayDetail> matches = partitionedDetails.get(true); // 匹配的项
        List<CustomerPayDetail> nonMatches = partitionedDetails.get(false); // 非匹配的项

        List<CustomerPayDetail> result = oneAndThreePayDetails.stream()
                .map(one -> {
                    Optional<CustomerPayDetail> match = matches.stream()
                            .filter(four -> Objects.equals(one.getType(), four.getType()) && Objects.equals(one.getResource(), four.getResource()))
                            .findFirst();
                    match.ifPresent(four -> one.setFourToSixMonthFees(four.getFourToSixMonthFees()));
                    return one;
                })
                .collect(Collectors.toList());

// 对于非匹配的项，根据业务逻辑决定如何处理，这里假设直接添加到finalCollect
        finalCollect.addAll(nonMatches);
        return result;
    }
    private List<CustomerPayDetail> getOneAndThreeCollect(List<CustomerPayDetail> oneAndThreePayDetails, List<CustomerPayDetail> SixAbovePayDetails, List<CustomerPayDetail> finalCollect) {
        Map<Boolean, List<CustomerPayDetail>> partitionedDetails = SixAbovePayDetails.stream()
                .collect(Collectors.partitioningBy(six -> oneAndThreePayDetails.stream()
                        .anyMatch(one -> Objects.equals(one.getType(), six.getType()) && Objects.equals(one.getResource(), six.getResource()))));

        List<CustomerPayDetail> matches = partitionedDetails.get(true); // 匹配的项
        List<CustomerPayDetail> nonMatches = partitionedDetails.get(false); // 非匹配的项

        List<CustomerPayDetail> result = oneAndThreePayDetails.stream()
                .map(one -> {
                    Optional<CustomerPayDetail> match = matches.stream()
                            .filter(six -> Objects.equals(one.getType(), six.getType()) && Objects.equals(one.getResource(), six.getResource()))
                            .findFirst();
                    match.ifPresent(six -> one.setFourToSixMonthFees(six.getFourToSixMonthFees()));
                    return one;
                })
                .collect(Collectors.toList());
        finalCollect.addAll(nonMatches);
    return result;
    }

    //查询所有组织下的所有子组织
    public void findAllOrganizationId(List<Integer> id,List<Integer> result) {
        result.addAll(id);
        //通过传进来的组织id查询出关联了它的所有组织id
        List<Integer> organizationIds = g3ProjectMapper.findAllOrganizationId(id);
            if (organizationIds.isEmpty()){
                return ;
            }
            findAllOrganizationId(organizationIds,result);
        return ;
    }
}
